﻿using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Scpi.Core.Business.hoster
{
    public class TcpClientHoster : IHoster, IHosterLisener
    {
        private TcpClient _tcpClient;

        public TcpClientHoster()
        {
            _tcpClient = new TcpClient();
        }

        public async Task ConnectAsync(ICommunicationParam communicationParam)
        {
            try
            {
                var netComParam = communicationParam as NetWorkCommunicationParam;

                if (netComParam == null)
                {
                    throw new ArgumentException("无法将参数拆箱成 NetWorkCommunicationParam类型");
                }
                await ConnectToServerAsync(netComParam).ConfigureAwait(false);
            }
            catch (Exception)
            {
                throw;
            }
        }

        public void Disconnect()
        {
            _tcpClient?.Close();

        }

        public bool GetIsConnect()
        {
            if (_tcpClient != null)
            {
                return _tcpClient.Connected;
            }
            else
            {
                return false;
            }
        }

        public int RecvData(out List<byte> buffer)
        {
            throw new NotImplementedException();
        }
        public async Task<string> RecvData()
        {
            try
            {
                var recvTask = await ReceiveDataAsync().ConfigureAwait(false);
                return recvTask;
            }
            catch (Exception)
            {
                throw;
            }
        }

        public async Task SendData(string buffer)
        {
            var sendBuffer = Encoding.ASCII.GetBytes(buffer);

            await sendDataAsync(sendBuffer);
        }

        public async Task<string> SendDataWitchRecvAsync(string buffer)
        {
            await SendData(buffer);
            return await ReceiveDataAsync();
        }

        private async Task sendDataAsync(byte[] buffer)
        {
            try
            {
                var networkStream = _tcpClient.GetStream();

                if (networkStream != null && _tcpClient.Connected == true)
                {
                    if (networkStream.CanWrite && buffer != null && buffer.Length > 0)
                    {
                        await networkStream.WriteAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
                        await networkStream.FlushAsync().ConfigureAwait(false);
                    }
                }
                else
                {
                    throw new Exception("TCP连接未准备好");
                }
            }
            catch (Exception)
            {

                throw;
            }
        }

        /// <summary>
        /// 根据服务器Ip地址和服务器活动端口，通过TCP与服务器建立通信链路。
        /// </summary>
        private async Task ConnectToServerAsync(NetWorkCommunicationParam netWorkCommunicationParam)
        {
            try
            {
                //开始异步连接服务器
                await _tcpClient.ConnectAsync(netWorkCommunicationParam.IpAddress, netWorkCommunicationParam.Port).ConfigureAwait(false);
            }
            catch (SocketException ex) when (ex.ErrorCode == 0x2748)
            {
                _tcpClient.Close();
                _tcpClient.Dispose();
                _tcpClient = new TcpClient();
                throw;
            }
            catch (Exception)
            {
                throw;
            }
        }

        private async Task<string> ReceiveDataAsync()
        {
            try
            {
                byte[] recvBuffer = new byte[1024];
                var networkStream = _tcpClient.GetStream();
                if (networkStream != null && _tcpClient.Connected == true)
                {
                    CancellationTokenSource cts = new CancellationTokenSource();
                    cts.CancelAfter(10000);
                    var recvdata = await networkStream.ReadAsync(recvBuffer, 0, recvBuffer.Length, cts.Token).ConfigureAwait(false);

                    if (recvdata > 0)
                    {
                        return Encoding.ASCII.GetString(recvBuffer, 0, recvdata);
                    }
                    else
                    {
                        return string.Empty;
                    }
                }
                else
                {
                    throw new Exception("TCP连接未准备好");
                }
            }
            catch (OperationCanceledException)
            {
                return string.Empty;
            }
            catch (Exception)
            {
                throw;
            }
        }
    }
}
